import { formatToUTC8 } from '../utils/time.utils';

/**
 * 模拟账户服务 (SimulatedAccount)
 *
 * 该类负责在回测过程中管理虚拟资产、处理交易指令，并记录所有活动。
 * 它模拟了真实交易中的资金流动、仓位变化和手续费计算，是回测框架的核心组件之一。
 */
export class SimulatedAccount {
  private readonly initialBalance: number; // 回测开始时的初始资金
  private quoteBalance: number;           // 计价货币的余额 (例如: USDT)
  private baseBalance: number;            // 交易货币的余额 (例如: BTC)
  private readonly feeRate: number;        // 每次交易的手续费率 (例如: 0.001 表示 0.1%)

  public trades: any[] = []; // 用于存储每一笔成功执行的交易记录
  private peakValue: number; // 用于跟踪资产峰值
  private maxDrawdown: number = 0; // 用于记录最大回撤率

  /**
   * @param {number} initialBalance - 初始投入的资金。
   * @param {number} [feeRate=0.001] - 交易手续费率，默认为 0.1%。
   */
  constructor(initialBalance: number, feeRate: number = 0.001) {
    this.initialBalance = initialBalance;
    this.quoteBalance = initialBalance;
    this.baseBalance = 0;
    this.feeRate = feeRate;
    this.peakValue = initialBalance; // 初始峰值为初始资金
  }

  /**
   * 执行买入操作。
   * 使用当前所有的计价货币（如USDT）按指定价格买入交易货币（如BTC）。
   *
   * @param {number} price - 当前的买入价格。
   * @param {number} timestamp - 交易发生时的时间戳。
   */
  public buy(price: number, timestamp: number): void {
    // 只有在有足够资金时才执行买入
    if (this.quoteBalance > 1) { // 留有余地，避免精度问题
      const amountToBuy = this.quoteBalance / price;
      const fee = amountToBuy * this.feeRate;
      this.baseBalance = amountToBuy - fee;
      this.quoteBalance = 0;
      this.logTrade('BUY', price, this.baseBalance, timestamp);
      this.updateDrawdown(price);
    }
  }

  /**
   * 执行卖出操作。
   * 将当前所有的交易货币（如BTC）按指定价格卖出，换成计价货币（如USDT）。
   *
   * @param {number} price - 当前的卖出价格。
   * @param {number} timestamp - 交易发生时的时间戳。
   */
  public sell(price: number, timestamp: number): void {
    // 只有在持有交易货币时才执行卖出
    if (this.baseBalance > 0) {
      const amountToSell = this.baseBalance;
      const quoteReceived = amountToSell * price;
      const fee = quoteReceived * this.feeRate;
      this.quoteBalance = quoteReceived - fee;
      this.baseBalance = 0;
      this.logTrade('SELL', price, amountToSell, timestamp);
      this.updateDrawdown(price);
    }
  }

  /**
   * 更新最大回撤率
   * @param currentPrice - 当前市价
   */
  private updateDrawdown(currentPrice: number): void {
    const currentValue = this.getTotalValue(currentPrice);

    // 更新资产峰值
    if (currentValue > this.peakValue) {
      this.peakValue = currentValue;
    }

    // 计算当前回撤
    const drawdown = (this.peakValue - currentValue) / this.peakValue;

    // 更新最大回撤
    if (drawdown > this.maxDrawdown) {
      this.maxDrawdown = drawdown;
    }
  }

  /**
   * 获取当前账户的总资产价值。
   * 总价值 = 计价货币余额 + (交易货币余额 * 当前市价)。
   *
   * @param {number} currentPrice - 用于计算资产总值的当前市场价格。
   * @returns {number} - 账户总价值。
   */
  public getTotalValue(currentPrice: number): number {
    return this.quoteBalance + this.baseBalance * currentPrice;
  }

  /**
   * 记录一笔交易的详细信息。
   */
  private logTrade(side: 'BUY' | 'SELL', price: number, amount: number, timestamp: number): void {
    const tradeInfo = {
      side,
      price,
      amount,
      timestamp,
      totalValue: this.getTotalValue(price),
    };
    this.trades.push(tradeInfo);
    console.log(`[TRADE] ${formatToUTC8(new Date(timestamp))} | ${side.padEnd(4)} | Price: ${price.toFixed(4)} | Amount: ${amount.toFixed(6)} | Value: ${tradeInfo.totalValue.toFixed(2)}`);
  }

  /**
   * 在每个K线周期结束后，更新账户的未实现盈亏和回撤
   * @param kline - 当前K线数据
   */
  public updatePnlAndDrawdown(kline: { close: number }): void {
    this.updateDrawdown(kline.close);
  }

  /**
   * 在回测结束后，打印详细的回测结果报告。
   *
   * @param {number} finalPrice - 最后一根K线的价格，用于计算最终总资产。
   */
  public printResults(finalPrice: number): void {
    const finalValue = this.getTotalValue(finalPrice);
    const profit = finalValue - this.initialBalance;
    const profitRate = (profit / this.initialBalance) * 100;
    const buyAndHoldValue = (this.initialBalance / this.trades[0]?.price) * finalPrice || this.initialBalance;
    const buyAndHoldReturn = ((buyAndHoldValue - this.initialBalance) / this.initialBalance) * 100;


    console.log("\n--- Backtest Results ---");
    console.log(`Initial Balance: ${this.initialBalance.toFixed(2)} USDT`);
    console.log(`Final Balance  : ${finalValue.toFixed(2)} USDT`);
    console.log(`Total Profit   : ${profit.toFixed(2)} USDT`);
    console.log(`Return Rate    : ${profitRate.toFixed(2)}%`);
    console.log(`Max Drawdown   : ${(this.maxDrawdown * 100).toFixed(2)}%`);
    console.log(`Buy & Hold Return: ${buyAndHoldReturn.toFixed(2)}%`);
    console.log(`Total Trades   : ${this.trades.length}`);
    console.log("------------------------\n");
  }
}
